/*
 * Vector3.h
 *
 * Created 11/29/2008 By Johnny Huynh
 *
 * Version 00.00.04 7/6/2009
 *
 * Copyright Information:
 * All content copyright © 2008-2009 Johnny Huynh. All rights reserved.
 */
 
 // Vector3.h contains all the vector functions

 #ifndef VECTOR3_H
 #define VECTOR3_H
 
 #include "OpenGL_Headers.h"
 #include "macro.h"
 
 template <typename TYPENAME> class Vector3;
 
 typedef Vector3<GLfloat> Vector3f;
 typedef Vector3<GLdouble> Vector3d;
 
 #include <math.h>
 
 // Global Functions (Under Vector namespace)
 namespace Vector
 {
    template <typename TYPENAME> inline static TYPENAME dotProduct( 
                                    const TYPENAME& Ax, const TYPENAME& Ay, const TYPENAME& Az, 
                                    const TYPENAME& Bx, const TYPENAME& By, const TYPENAME& Bz );
    template <typename TYPENAME> inline static Vector3<TYPENAME> crossProduct( 
                                    const TYPENAME& Ax, const TYPENAME& Ay, const TYPENAME& Az, 
                                    const TYPENAME& Bx, const TYPENAME& By, const TYPENAME& Bz );
    template <typename TYPENAME> inline static void normalize( TYPENAME& x, TYPENAME& y, TYPENAME& z );
 }
 
 template <typename TYPENAME>
 class Vector3
 {
 // Data Members
 public:
    TYPENAME x, y, z;   // contained in order of OpenGL notation (x, y, z)
 
 // Local Functions
 public:
    Vector3( const TYPENAME& x_coordinate = ZERO, const TYPENAME& y_coordinate = ZERO, const TYPENAME& z_coordinate = ZERO );
    Vector3( const Vector3<TYPENAME>& u );
    ~Vector3();
    inline Vector3<TYPENAME>& operator=( const Vector3<TYPENAME>& u );
    inline Vector3<TYPENAME>& operator+=( const Vector3<TYPENAME>& u );
    inline Vector3<TYPENAME>& operator-=( const Vector3<TYPENAME>& u );
    inline Vector3<TYPENAME>& operator*=( const Vector3<TYPENAME>& u );
    inline Vector3<TYPENAME>& operator/=( const Vector3<TYPENAME>& u );
    inline Vector3<TYPENAME>& operator*=( const TYPENAME& s );
    inline Vector3<TYPENAME>& operator/=( const TYPENAME& s );
    inline TYPENAME& operator[]( const size_t& i );
    inline const TYPENAME& operator[]( const size_t& i ) const;
    inline Vector3<TYPENAME>& copy( const Vector3<TYPENAME>& u );
    inline Vector3<TYPENAME> crossProduct( const Vector3<TYPENAME>& u ) const;
    inline TYPENAME dotProduct( const Vector3<TYPENAME>& u ) const;
    inline TYPENAME dotProduct( const TYPENAME& Bx, const TYPENAME& By, const TYPENAME& Bz ) const;
    inline const TYPENAME * getArray() const;
    inline TYPENAME getMagnitude() const;
    inline TYPENAME getMagnitudeSquared() const;
    inline bool isZeroVector() const;
    inline Vector3<TYPENAME>& normalize();
    inline Vector3<TYPENAME> getNormal() const;
 
 // Private Functions
 private:
    
 // Friend Functions
 public:
    template <typename TYPENAME> friend inline bool operator==( const Vector3<TYPENAME>& u, const Vector3<TYPENAME>& v );
    template <typename TYPENAME> friend inline bool operator!=( const Vector3<TYPENAME>& u, const Vector3<TYPENAME>& v );
    template <typename TYPENAME> friend inline Vector3<TYPENAME> operator+( const Vector3<TYPENAME>& u, const Vector3<TYPENAME>& v );
    template <typename TYPENAME> friend inline Vector3<TYPENAME> operator-( const Vector3<TYPENAME>& u, const Vector3<TYPENAME>& v );
    template <typename TYPENAME> friend inline Vector3<TYPENAME> operator-( const Vector3<TYPENAME>& u );
    template <typename TYPENAME> friend inline Vector3<TYPENAME> operator*( const TYPENAME& s, const Vector3<TYPENAME>& u );
    template <typename TYPENAME> friend inline Vector3<TYPENAME> operator*( const Vector3<TYPENAME>& u, const TYPENAME& s );
    template <typename TYPENAME> friend inline TYPENAME operator*( const Vector3<TYPENAME>& u, const Vector3<TYPENAME>& v );
    template <typename TYPENAME> friend inline Vector3<TYPENAME> operator/( const Vector3<TYPENAME>& u, const TYPENAME& s );
    template <typename TYPENAME> friend inline Vector3<TYPENAME> crossProduct( const Vector3<TYPENAME>& u, const Vector3<TYPENAME>& v );
    template <typename TYPENAME> friend inline TYPENAME dotProduct( const Vector3<TYPENAME>& u, const Vector3<TYPENAME>& v );
    template <typename TYPENAME> friend inline Vector3<TYPENAME> fabs( const Vector3<TYPENAME>& u );
    template <typename TYPENAME> friend inline TYPENAME magnitude( const Vector3<TYPENAME>& u );
    template <typename TYPENAME> friend inline TYPENAME magnitude_squared( const Vector3<TYPENAME>& u );
    template <typename TYPENAME> friend inline Vector3<TYPENAME> normal( const Vector3<TYPENAME>& u );
    template <typename TYPENAME> friend inline Vector3<TYPENAME>& normalize( Vector3<TYPENAME>& u );
    template <typename TYPENAME> friend inline void findMaxProjectionExtent( const Vector3<TYPENAME>& vector, 
                                                                             const Vector3<TYPENAME>& axis, TYPENAME& max );
    template <typename TYPENAME> friend inline void findMinMaxProjectionExtent( const Vector3<TYPENAME>& vector, 
                                                                const Vector3<TYPENAME>& axis, TYPENAME& min, TYPENAME& max );
    template <typename TYPENAME> friend inline void print( const Vector3<TYPENAME>& u );
 };
 
 
 
 /** GLOBAL FUNCTIONS (Under Vector namespace) **/

 /**
  * dotProduct() returns the dot product between the two supplied vectors.
  *
  * @param (const TYPENAME&) Ax
  * @param (const TYPENAME&) Ay
  * @param (const TYPENAME&) Az 
  * @param (const TYPENAME&) Bx
  * @param (const TYPENAME&) By
  * @param (const TYPENAME&) Bz
  * @return TYPENAME
  */
 template <typename TYPENAME>
 inline static TYPENAME Vector::dotProduct( const TYPENAME& Ax, const TYPENAME& Ay, const TYPENAME& Az, 
                                            const TYPENAME& Bx, const TYPENAME& By, const TYPENAME& Bz )
 {
    return (Ax*Bx) + (Ay*By) + (Az*Bz);
 }
 
 /**
  * crossProduct() returns the cross product between the two supplied vectors.
  *
  * @param (const TYPENAME&) Ax
  * @param (const TYPENAME&) Ay
  * @param (const TYPENAME&) Az 
  * @param (const TYPENAME&) Bx
  * @param (const TYPENAME&) By
  * @param (const TYPENAME&) Bz
  * @return Vector3<TYPENAME>
  */
 template <typename TYPENAME>
 inline static Vector3<TYPENAME> Vector::crossProduct( const TYPENAME& Ax, const TYPENAME& Ay, const TYPENAME& Az, 
                                                       const TYPENAME& Bx, const TYPENAME& By, const TYPENAME& Bz )
 {
    // AyBz - AzBy, -AxBz + AzBx, AxBy - AyBx
    return Vector3<TYPENAME>( (Ay*Bz) - (Az*By), (Az*Bx) - (Ax*Bz), (Ax*By) - (Ay*Bx) );
 }
 
 /**
  * normalize() normalizes the 3 specified coordinates of a vector,
  * such that the vector becomes a unit vector.
  *
  * @param (TYPENAME&) x
  * @param (TYPENAME&) y
  * @param (TYPENAME&) z
  */
 template <typename TYPENAME>
 inline void Vector::normalize( TYPENAME& x, TYPENAME& y, TYPENAME& z )
 {
    TYPENAME m( sqrt( (x*x) + (y*y) + (z*z) ) );
    
    // Prevent divide by zero
    if ( m != ZERO )
    {
        x /= m;
        y /= m;
        z /= m;
    }
 }

 /** LOCAL FUNCTIONS **/
 
 /**
  * Constructor
  */
 template <typename TYPENAME>
 Vector3<TYPENAME>::Vector3( const TYPENAME& x_coordinate, const TYPENAME& y_coordinate, const TYPENAME& z_coordinate )
                        : x( x_coordinate ), y( y_coordinate ), z( z_coordinate )
 {
    
 }
 
 /**
  * Alternative Constructor
  */
 template <typename TYPENAME>
 Vector3<TYPENAME>::Vector3( const Vector3<TYPENAME>& u ) : x( u.x ), y( u.y ), z( u.z )
 {
    
 }
 
 /**
  * Destructor
  */
 template <typename TYPENAME>
 Vector3<TYPENAME>::~Vector3()
 {
 
 }
 
 /**
  * operator=() copies the values of the vector u
  * and returns the vector (referenced).
  * It returns a reference to itself, not vector u.
  *
  * @param (const Vector3<TYPENAME>&) u
  * @return Vector3<TYPENAME>&
  */
 template <typename TYPENAME>
 inline Vector3<TYPENAME>& Vector3<TYPENAME>::operator=( const Vector3<TYPENAME>& u )
 {  
    memcpy( this, &u, sizeof(Vector3<TYPENAME>) );
    return *this;
 }
 
 /**
  * operator+=() add the values of the vector u
  * to this vector and returns this vector (referenced).
  *
  * @param (const Vector3<TYPENAME>&) u
  * @return Vector3<TYPENAME>&
  */
 template <typename TYPENAME>
 inline Vector3<TYPENAME>& Vector3<TYPENAME>::operator+=( const Vector3<TYPENAME>& u )
 {
    x += u.x;
    y += u.y;
    z += u.z;
    return *this;
 }
 
 /**
  * operator-=() subtracts the values of the vector u
  * from this vector and returns this vector (referenced).
  *
  * @param (const Vector3<TYPENAME>&) u
  * @return Vector3<TYPENAME>&
  */
 template <typename TYPENAME>
 inline Vector3<TYPENAME>& Vector3<TYPENAME>::operator-=( const Vector3<TYPENAME>& u )
 {
    x -= u.x;
    y -= u.y;
    z -= u.z;
    return *this;
 }
 
 /**
  * operator*=() the values of this vector are multiplied with
  * the values of the vector u, and this vector is returned (referenced).
  *
  * @param (const Vector3<TYPENAME>&) u
  * @return Vector3<TYPENAME>&
  */
 template <typename TYPENAME>
 inline Vector3<TYPENAME>& Vector3<TYPENAME>::operator*=( const Vector3<TYPENAME>& u )
 {
    x *= u.x;
    y *= u.y;
    z *= u.z;
    return *this;
 }
 
 /**
  * operator/=() the values of this vector are divided by
  * the values of the vector u, and this vector is returned (referenced).
  *
  * @param (const Vector3<TYPENAME>&) u
  * @return Vector3<TYPENAME>&
  */
 template <typename TYPENAME>
 inline Vector3<TYPENAME>& Vector3<TYPENAME>::operator/=( const Vector3<TYPENAME>& u )
 {
    x /= u.x;
    y /= u.y;
    z /= u.z;
    return *this;
 }
 
 /**
  * operator/=() the values of this vector are multiplied by
  * the specified scalar, and this vector is returned (referenced).
  *
  * @param (const TYPENAME&) s
  * @return Vector3<TYPENAME>&
  */
 template <typename TYPENAME>
 inline Vector3<TYPENAME>& Vector3<TYPENAME>::operator*=( const TYPENAME& s )
 {
    x *= s;
    y *= s;
    z *= s;
    return *this;
 }
 
 /**
  * operator/=() the values of this vector are divided by
  * the specified scalar, and this vector is returned (referenced).
  *
  * @param (const TYPENAME&) s
  * @return Vector3<TYPENAME>&
  */
 template <typename TYPENAME>
 inline Vector3<TYPENAME>& Vector3<TYPENAME>::operator/=( const TYPENAME& s )
 {
    x /= s;
    y /= s;
    z /= s;
    return *this;
 }
 
 /**
  * operator[]() returns the ith element of the vector.
  * Note that 0 <= i <= 2.
  *
  * @param (const size_t&) i
  * @return TYPENAME&
  */
 template <typename TYPENAME>
 inline TYPENAME& Vector3<TYPENAME>::operator[]( const size_t& i )
 {
    return reinterpret_cast<TYPENAME*>(this)[i];
 }
 
 /**
  * operator[]() returns the ith element of the vector.
  * Note that 0 <= i <= 2.
  *
  * @param (const size_t&) i
  * @return const TYPENAME&
  */
 template <typename TYPENAME>
 inline const TYPENAME& Vector3<TYPENAME>::operator[]( const size_t& i ) const
 {
    return reinterpret_cast<TYPENAME*>(this)[i];
 }
 
 /**
  * copy() copies the values of the vector u
  * and returns this vector (referenced).
  * It returns a reference to itself, not vector u.
  *
  * @param (const Vector3<TYPENAME>&) u
  * @return Vector3<TYPENAME>&
  */
 template <typename TYPENAME>
 inline Vector3<TYPENAME>& Vector3<TYPENAME>::copy( const Vector3<TYPENAME>& u )
 {
    memcpy( this, &u, sizeof(Vector3<TYPENAME>) );
    return *this;
 }

 /**
  * crossProduct() returns the cross product between this vector and the supplied vector.
  *
  * @param (const Vector3<TYPENAME>&) u
  * @return Vector3<TYPENAME>
  */
 template <typename TYPENAME>
 inline Vector3<TYPENAME> Vector3<TYPENAME>::crossProduct( const Vector3<TYPENAME>& u ) const
 {
    // AyBz - AzBy, -AxBz + AzBx, AxBy - AyBx
    return Vector3<TYPENAME>( (y*u.z) - (z*u.y), (z*u.x) - (x*u.z), (x*u.y) - (y*u.x) );
 }
 
 /**
  * dotProduct() returns the dot product between this vector and the specified coordinates of a vector.
  *
  * @param (const TYPENAME&) Bx
  * @param (const TYPENAME&) By
  * @param (const TYPENAME&) Bz
  * @return TYPENAME
  */
 template <typename TYPENAME>
 inline TYPENAME Vector3<TYPENAME>::dotProduct( const TYPENAME& Bx, const TYPENAME& By, const TYPENAME& Bz ) const
 {
    return (x*Bx) + (y*By) + (z*Bz);
 }
 
 /**
  * dotProduct() returns the dot product between this vector and the supplied vector.
  *
  * @param (const Vector3<TYPENAME>&) u
  * @return TYPENAME
  */
 template <typename TYPENAME>
 inline TYPENAME Vector3<TYPENAME>::dotProduct( const Vector3<TYPENAME>& u ) const
 {
    return (*this)*u;
 }
 
 /**
  * getArray() returns the OpenGL array representation of this vector (i.e. [x, y, z]).
  *
  * @return const TYPENAME *
  */
 template <typename TYPENAME>
 inline const TYPENAME * Vector3<TYPENAME>::getArray() const
 {
    return const_cast<const TYPENAME *>(this);
 }
 
 /**
  * getMagnitude() returns the magnitude of the vector.
  *
  * @return TYPENAME
  */
 template <typename TYPENAME>
 inline TYPENAME Vector3<TYPENAME>::getMagnitude() const
 {
    return sqrt( (x*x) + (y*y) + (z*z) );
 }
 
 /**
  * getMagnitudeSquared() returns the magnitude squared of the vector.
  *
  * @return TYPENAME
  */
 template <typename TYPENAME>
 inline TYPENAME Vector3<TYPENAME>::getMagnitudeSquared() const
 {
    return (x*x) + (y*y) + (z*z);
 }

 /**
  * isZeroVector() returns true if this vector is the zero vector;
  * otherwise, false is returned.
  *
  * @return bool
  */
 template <typename TYPENAME>
 inline bool Vector3<TYPENAME>::isZeroVector() const
 {
    return !(x || y || z);
 }

 /**
  * normalize() converts this vector into a unit vector and 
  * returns a reference to this vector.
  *
  * @return Vector3<TYPENAME>&
  */
 template <typename TYPENAME>
 inline Vector3<TYPENAME>& Vector3<TYPENAME>::normalize()
 {
    TYPENAME m( sqrt( (x*x) + (y*y) + (z*z) ) );
    
    // Prevent divide by zero
    if ( m == ZERO )
        return *this;
    
    x /= m;
    y /= m;
    z /= m;
    return *this;
 }
 
 /**
  * getNormal() returns a normalized copy of this vector.
  * Notice this vector is not altered.
  * Instead, a newly created vector is modified.
  *
  * @return Vector3<TYPENAME>
  */
 template <typename TYPENAME>
 inline Vector3<TYPENAME> Vector3<TYPENAME>::getNormal() const
 {
    TYPENAME m( sqrt( (x*x) + (y*y) + (z*z) ) );
    
    // Prevent divide by zero
    if ( m == ZERO )
        return *this;
    
    Vector3<TYPENAME> v( *this );
    
    v.x /= m;
    v.y /= m;
    v.z /= m;
    return v;
 }
 

 /** FRIEND FUNCTIONS **/
 
  /**
  * operator==() returns true if the two specified vectors are equal;
  * otherwise, false is returned.
  *
  * @param (const Vector3<TYPENAME>&) u
  * @param (const Vector3<TYPENAME>&) v
  * @return bool
  */
 template <typename TYPENAME>
 inline bool operator==( const Vector3<TYPENAME>& u, const Vector3<TYPENAME>& v )
 {  
    return u.x == v.x && u.y == v.y && u.z == v.z;
 }
 
 /**
  * operator!=() returns true if the two specified vectors are not equal;
  * otherwise, false is returned.
  *
  * @param (const Vector3<TYPENAME>&) u
  * @param (const Vector3<TYPENAME>&) v
  * @return bool
  */
 template <typename TYPENAME>
 inline bool operator!=( const Vector3<TYPENAME>& u, const Vector3<TYPENAME>& v )
 {  
    return u.x != v.x || u.y != v.y || u.z != v.z;
 }
 
 /**
  * operator+() returns a vector constituting the addition 
  * between the two supplied vectors (i.e. u + v).
  *
  * @param (const Vector3<TYPENAME>&) u
  * @param (const Vector3<TYPENAME>&) v
  * @return Vector3<TYPENAME>
  */
 template <typename TYPENAME>
 inline Vector3<TYPENAME> operator+( const Vector3<TYPENAME>& u, const Vector3<TYPENAME>& v )
 {
    return Vector3<TYPENAME>( u.x + v.x, u.y + v.y, u.z + v.z );
 }

 /**
  * operator-() returns a vector constituting the subtraction 
  * between the two supplied vectors (i.e. u - v).
  *
  * @param (const Vector3<TYPENAME>&) u
  * @param (const Vector3<TYPENAME>&) v
  * @return Vector3<TYPENAME>
  */
 template <typename TYPENAME>
 inline Vector3<TYPENAME> operator-( const Vector3<TYPENAME>& u, const Vector3<TYPENAME>& v )
 {
    return Vector3<TYPENAME>( u.x - v.x, u.y - v.y, u.z - v.z );
 }

 /**
  * operator-() returns a vector with the values
  * of vector u negated (i.e. (-u.x, -u.y, -u.z)).
  *
  * @param (const Vector3<TYPENAME>&) u
  * @return Vector3<TYPENAME>
  */
 template <typename TYPENAME>
 inline Vector3<TYPENAME> operator-( const Vector3<TYPENAME>& u )
 {
    return Vector3<TYPENAME>( -u.x, -u.y, -u.z );
 }

 /**
  * operator*() returns the product of a scalar and a vector.
  *
  * @param (const TYPENAME&) s
  * @param (const Vector3<TYPENAME>&) u
  * @return Vector3<TYPENAME>
  */
 template <typename TYPENAME>
 inline Vector3<TYPENAME> operator*( const TYPENAME& s, const Vector3<TYPENAME>& u )
 {
    return Vector3<TYPENAME>( s*u.x, s*u.y, s*u.z );
 }

 /**
  * operator*() returns the product of a scalar and a vector.
  *
  * @param (const Vector3<TYPENAME>&) u
  * @param (const TYPENAME&) s
  * @return Vector3<TYPENAME>
  */
 template <typename TYPENAME>
 inline Vector3<TYPENAME> operator*( const Vector3<TYPENAME>& u, const TYPENAME& s )
 {
    return s*u;
 }

 /**
  * operator*() returns the dot product between the two supplied vectors.
  *
  * @param (const Vector3<TYPENAME>&) u
  * @param (const Vector3<TYPENAME>&) v
  * @return TYPENAME
  */
 template <typename TYPENAME>
 inline TYPENAME operator*( const Vector3<TYPENAME>& u, const Vector3<TYPENAME>& v )
 {
    return (u.x*v.x) + (u.y*v.y) + (u.z*v.z);
 }

 /**
  * operator/() returns the division of a vector by a scalar.
  *
  * @param (const Vector3<TYPENAME>&) u
  * @param (const TYPENAME&) s
  * @return Vector3<TYPENAME>
  */
 template <typename TYPENAME>
 inline Vector3<TYPENAME> operator/( const Vector3<TYPENAME>& u, const TYPENAME& s )
 {
    return Vector3<TYPENAME>( u.x/s, u.y/s, u.z/s );
 }

 /**
  * crossProduct() returns the cross product between the two supplied vectors.
  *
  * @param (const Vector3<TYPENAME>&) u
  * @param (const Vector3<TYPENAME>&) v
  * @return Vector3<TYPENAME>
  */
 template <typename TYPENAME>
 inline Vector3<TYPENAME> crossProduct( const Vector3<TYPENAME>& u, const Vector3<TYPENAME>& v )
 {
    // AyBz - AzBy, -AxBz + AzBx, AxBy - AyBx
    return Vector3<TYPENAME>( (u.y*v.z) - (u.z*v.y), (u.z*v.x) - (u.x*v.z), (u.x*v.y) - (u.y*v.x) );
 }

 /**
  * dotProduct() returns the dot product between the two supplied vectors.
  *
  * @param (const Vector3<TYPENAME>&)u
  * @param (const Vector3<TYPENAME>&)v
  * @return TYPENAME
  */
 template <typename TYPENAME>
 inline TYPENAME dotProduct( const Vector3<TYPENAME>& u, const Vector3<TYPENAME>& v )
 {
    return u.x*v.x + u.y*v.y + u.z*v.z;
 }
 
 /**
  * fabs() returns the absolute value of the specified vector.
  *
  * @param (const Vector3<TYPENAME>&) u
  * @return Vector3<TYPENAME
  */
 template <typename TYPENAME> 
 inline Vector3<TYPENAME> fabs( const Vector3<TYPENAME>& u )
 {
    return Vector3<TYPENAME>( FABS( u.x ), FABS( u.y ), FABS( u.z ) );
 }
 
 /**
  * magnitude() returns the magnitude of the vector.
  *
  * @return TYPENAME
  */
 template <typename TYPENAME>
 inline TYPENAME magnitude( const Vector3<TYPENAME>& u )
 {
    return sqrt( (u.x*u.x) + (u.y*u.y) + (u.z*u.z) );
 }
 
 /**
  * magnitude_squared() returns the magnitude squared of the vector.
  *
  * @return TYPENAME
  */
 template <typename TYPENAME>
 inline TYPENAME magnitude_squared( const Vector3<TYPENAME>& u )
 {
    return (u.x*u.x) + (u.y*u.y) + (u.z*u.z);
 }

 /**
  * normal() returns the unit vector form of the specified vector.
  *
  * @param (const Vector3<TYPENAME>&)u
  * @return Vector3<TYPENAME>
  */
 template <typename TYPENAME>
 inline Vector3<TYPENAME> normal( const Vector3<TYPENAME>& u )
 {
    TYPENAME m( sqrt( (u.x*u.x) + (u.y*u.y) + (u.z*u.z) ) );
    
    // Prevent divide by zero
    if ( m == ZERO )
        return u;
    
    Vector3<TYPENAME> v( u );   // make a new vector that copies the content of u
    
    v.x /= m;
    v.y /= m;
    v.z /= m;
    return v;
 }

 /**
  * normalize() converts the vector into a unit vector and 
  * returns a reference to the vector.
  *
  * @param (Vector3<TYPENAME>&)u
  * @return Vector3<TYPENAME>&
  */
 template <typename TYPENAME>
 inline Vector3<TYPENAME>& normalize( Vector3<TYPENAME>& u )
 {
    TYPENAME m( sqrt( (u.x*u.x) + (u.y*u.y) + (u.z*u.z) ) );
    
    // Prevent divide by zero
    if ( m == ZERO )
        return u;
    
    u.x /= m;
    u.y /= m;
    u.z /= m;
    return u;
 }
 
  /**
  * findMaxProjectionExtent() adjusts the specified max to reflect the projection of the 
  * specified vector onto the specified axis if the projection value is greater than max.
  * Notice because we are only concerned with the length of the projection, we use the
  * absolute value of the projection for the specified max.
  *
  * @param (const Vector3<TYPENAME>&) vector
  * @param (const Vector3<TYPENAME>&) axis
  * @param (TYPENAME&) max
  */
 template <typename TYPENAME>
 inline void findMaxProjectionExtent( const Vector3<TYPENAME>& vector, const Vector3<TYPENAME>& axis, TYPENAME& max )
 {
    TYPENAME extent( vector * axis ); // project the point onto the axis (i.e. unit vector)
    
    if ( extent < ZERO )
        extent = fabs( extent );
    
    if ( extent > max )
        max = extent;
 }
 
 /**
  * findMinMaxProjectionExtent() adjusts the specified min and max to reflect the projection 
  * of the specified vector onto the specified axis if the projection value is less than min 
  * or greater than max respectively.
  *
  * @param (const Vector3<TYPENAME>&) vector
  * @param (const Vector3<TYPENAME>&) axis
  * @param (TYPENAME&) min
  * @param (TYPENAME&) max
  */
 template <typename TYPENAME>
 inline void findMinMaxProjectionExtent( const Vector3<TYPENAME>& vector, const Vector3<TYPENAME>& axis, 
                                         TYPENAME& min, TYPENAME& max )
 {
    TYPENAME extent( vector * axis ); // project the point onto the axis (i.e. unit vector)
    
    if ( extent > max )
        max = extent;
    else if ( extent < min )
        min = extent;
 }
 
 /**
  * print() prints out the coordinates of the vector.
  *
  * @param (const Vector3<TYPENAME>&)u 
  */
 template <typename TYPENAME>
 inline void print( const Vector3<TYPENAME>& u )
 {
    printf("(%1f, %2f, %3f)\n", u.x, u.y, u.z);
 }
 
 
 #endif // VECTOR3_H